
from multiprocessing import Process,Queue
import os
import time
import random
import multiprocessing
import threading


def worker(count, queue:Queue):
    print(f"ProcessId:{os.getpid()} produce {count} random number")
    list1 = list(range(1,count))
    for i in list1:
        randomData = random.randint(0,10000)
        if queue is None:
            continue
        queue.put(randomData)
        # print(f"ProcessId:{os.getpid()}:worker execute ,produce :randomData:{randomData} \n")
    print(f"ProcessId:{os.getpid()} produce finish")

def workerWithoutQueue(count):
    print(f"ProcessId:{os.getpid()} produce {count} random number")
    print(f"thread:{threading.current_thread().name}:worker execute")
    list1 = list(range(1,count))
    for i in list1:
        randomData = random.randint(0,10000)
        # print(f"ProcessId:{os.getpid()}:worker execute ,produce :randomData:{randomData} \n")
    print(f"ProcessId:{os.getpid()} produce finish")


def buildSingleProcess():
   currentTime = time.time()* 1000
   print(f"ProcessId:{os.getpid()}:main executing")
   queue = Queue()
   p = Process(target=worker,args=[10000,queue])
   p.start()

   p2 = Process(target= listeningQueue,args=[queue])
   p2.start()
   p.join()
   
   print(f"woker finish")
   queue.put(None)
   queue.close()
   p2.join()
   useTime = time.time() *1000 - currentTime
   print(f"ProcessId:{os.getpid()}:main executed, use time:{useTime}")

def buildMultiProcess(count):
    print(f"multi process  executing")
    currentTime = time.time()* 1000
    queue = Queue()

    p2 = Process(target= listeningQueue,args=[queue])
    p2.start()
    processes =  [Process(target= worker, args= [100000//count,queue]) for _ in range(count)]
    
    for p in processes:
        p.start()

    for p in processes:
        p.join()
    print(f"woker finish")
    for p in processes:
        queue.put(None)
    queue.close()
    p2.join()
    useTime = time.time() *1000 - currentTime
    print(f"multi process executed, use time:{useTime}")



def buildMultiProcessWithPool(count):
    print(f"multi process  executing")
    currentTime = time.time()* 1000
    manager = multiprocessing.Manager()
    queue = manager.Queue()

    p2 = Process(target= listeningQueue,args=[queue])
    p2.start()
    with multiprocessing.Pool(processes=count) as pool:
        # [pool.apply_async(worker,args=[100000//count,queue]) for _ in range(count)]
        for _ in range(count):
            print(f"worker execute, \n")
            pool.apply_async(worker,args=[100000//count,queue])
        pool.close()
        pool.join()
   
    print(f"woker finish")
    queue.put(None)
    p2.join()
    useTime = time.time() *1000 - currentTime
    print(f"multi process executed, use time:{useTime}")


def listeningQueue(queue:Queue):
    while True:
      random_data = queue.get()
      if random_data is None:
        print("queue is empty")
        break
      print(f"ProcessId:{os.getpid()}:listener received random data: {random_data}")
    print(f"ProcessId:{os.getpid()}:listener finish")



def buildSingleThread():
   currentTime = time.time()* 1000
   print(f"Thread:{threading.current_thread().name}:main executing")
   t = threading.Thread(target=workerWithoutQueue,args=[10000],name="worker-1")   
   t.start()
   t.join()
   useTime = time.time() *1000 - currentTime
   print(f"Thread:{threading.current_thread().name}:main executed, use time:{useTime}")



a = 100

lock = threading.Lock()
def changeA(b):
   try:
    lock.acquire()
    global a
    a = a+b
    a = a-b
    print(f"Thread:{threading.current_thread().name}:changeA, a:{a}")
   finally:
    lock.release()

def buildMultiThread():
   currentTime = time.time()* 1000
   t = threading.Thread(target=changeA,args=[100],name="worker-1")
   t.start()
   t.join()
   t2 = threading.Thread(target=changeA,args=[100],name="worker-2")
   t2.start()
   t2.join()
   print(f"main finish,A= {a}")
 
   

if __name__ == "__main__":
   cpu_count = multiprocessing.cpu_count()
   print(f"Device Info: CPU Count:{cpu_count}") 
#    buildSingleProcess()
#    buildMultiProcess(cpu_count)
#    buildMultiProcessWithPool(cpu_count)
   buildSingleThread()
   buildMultiThread()
   


   

